fn size_of_type() {
    println!("\n---------- Test Size of Type -----------");
    println!("char:  ({}B)", std::mem::size_of::<char>());
    println!("bool:  ({}B)", std::mem::size_of::<bool>());
    println!("i8:    ({}B)", std::mem::size_of::<i8>());
    println!("i16:   ({}B)", std::mem::size_of::<i16>());
    println!("i32:   ({}B)", std::mem::size_of::<i32>());
    println!("i64:   ({}B)", std::mem::size_of::<i64>());
    println!("i128:  ({}B)", std::mem::size_of::<i128>());
    println!("isize: ({}B)", std::mem::size_of::<isize>());
    println!("u8:    ({}B)", std::mem::size_of::<u8>());
    println!("u16:   ({}B)", std::mem::size_of::<u16>());
    println!("u32:   ({}B)", std::mem::size_of::<u32>());
    println!("u64:   ({}B)", std::mem::size_of::<u64>());
    println!("u128:  ({}B)", std::mem::size_of::<u128>());
    println!("usize: ({}B)", std::mem::size_of::<usize>());
    println!("f32:   ({}B)", std::mem::size_of::<f32>());
    println!("f64:   ({}B)", std::mem::size_of::<f64>());
}

fn int_type() {
    let i8_val: i8 = 23;
    let i16_val: i16 = 23;
    let i32_val: i32 = 23;
    let i64_val: i64 = 23;
    let i128_val: i128 = 23;
    let isize_val: isize = 23;

    let u8_val: u8 = 23;
    let u16_val: u16 = 23;
    let u32_val: u32 = 23;
    let u64_val: u64 = 23;
    let u128_val: u128 = 23;
    let usize_val: usize = 23;

    println!("\n------------ Test Int Type ------------");
    println!("i8_val: {} i16_val: {} i32_val: {} i64_val: {} i128_val: {} isize_val: {}", i8_val, i16_val, i32_val, i64_val, i128_val, isize_val);
    println!("u8_val: {} u16_val: {} u32_val: {} u64_val: {} u128_val: {} usize_val: {}", u8_val, u16_val, u32_val, u64_val, u128_val, usize_val);
}

fn float_type() {
    let f32_val: f32 = 23.1;
    let f64_val: f64 = 23.1;

    println!("\n------------ Test Float Type ------------");
    println!("f32_val: {} f64_val: {}, f64_val + f64_val: {}", f32_val, f64_val, f64_val + f64_val);
}

fn float_compare() {
    let abc: (f32, f32, f32) = (0.1, 0.2, 0.3);
    let xyz: (f64, f64, f64) = (0.1, 0.2, 0.3);

    println!("abc (f32)");
    println!("   0.1 + 0.2: {:x}", (abc.0 + abc.1).to_bits());
    println!("         0.3: {:x}", (abc.2).to_bits());
    println!();

    println!("xyz (f64)");
    println!("   0.1 + 0.2: {:x}", (xyz.0 + xyz.1).to_bits());
    println!("         0.3: {:x}", (xyz.2).to_bits());
    println!();

    assert!(abc.0 + abc.1 == abc.2);
    // assert!(xyz.0 + xyz.1 == xyz.2);
}

fn nan() {
    let x = (-42.0_f32).sqrt();

    println!("\n--------------- Test nan  ---------------");
    println!("x: {}, x.is_nan(): {}", x, x.is_nan());
}

fn value_compute() {
    let sum = 5 + 10;
    let difference = 95.5 - 4.3;
    let product = 4 * 30;
    let quotient = 56.7 / 32.2;
    let remainder = 43 % 5;
    println!("\n----------- Test Value Compute ----------");
    println!("5 + 5 = {}", sum);
    println!("95.5 - 4.3 = {}", difference);
    println!("4 * 30 = {}", product);
    println!("56.7 / 32.2 = {}", quotient);
    println!("43 % 5 = {}", remainder);
}

fn bit_compute() {
    let a: u8 = 2;
    let b: u8 = 3;

    println!("\n------------ Test Bit Compute -----------");
    println!("{:08b} = {}", a, a);
    println!("{:08b} = {}", b, b);
    println!("{:08b} = ({} & {})", a & b, a, b);
    println!("{:08b} = ({} | {})", a | b, a, b);
    println!("{:08b} = ({} ^ {})", a ^ b, a, b);
    println!("{:08b} = (!{})", !b, b);
    println!("{:08b} = ({} << {})", a << b, a, b);
    println!("{:08b} = ({} >> {})", a >> b, a, b);
}

fn range() {
    let x = 5;
    let y = 10;
    let range = x..=y;
    println!("\n------------ Test Range ------------");
    println!("range: {:?}", range);
    for i in range {
        println!("{}", i);
    }
}

fn char() {
    let c = 'z';
    let z = 'ℤ';
    let g = '国';
    let heart_eyed_cat: char = '😻';
    println!("\n------------ Test Char ------------");
    println!("c: {}({}), z: {}({}), g: {}({}), heart_eyed_cat: {}({})", c, std::mem::size_of_val(&c),
        z, std::mem::size_of_val(&z), g, std::mem::size_of_val(&g), heart_eyed_cat, std::mem::size_of_val(&heart_eyed_cat));
}

fn expression() {
    let y = {
        let x = 3;
        x + 1
    };

    let z = if y % 2 == 1 { "odd" } else { "even" };

    println!("\n------------ Test Expression ------------");
    println!("y: {} z: {}", y, z);
}

fn abs(i: i32) -> i32 {
    if i < 0 {
        return -i
    }

    return i
}

fn test_add() {
    println!("\n------------- Test function -------------");
    println!("abs(-2) = {}", abs(-2));
    println!("abs(2) = {}", abs(2));
}

fn main() {
    size_of_type();
    int_type();
    float_type();
    float_compare();
    nan();
    value_compute();
    bit_compute();
    range();
    char();
    expression();
    test_add();
}
